use crate::MathUtils::MathUtils;

#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
pub struct Vector2 {
    pub x: f64,
    pub y: f64,
}

impl Vector2 {
    pub const ZERO: Vector2 = Vector2 { x: 0.0, y: 0.0 };

    pub fn new(x: f64, y: f64) -> Self {
        Self { x, y }
    }

    pub fn distance_squared(&self) -> f64 {
        self.x * self.x + self.y * self.y
    }

    pub fn slope(&self) -> f64 {
        self.y.atan2(self.x)
    }

    pub fn reverse(&self) -> Self {
        Self {
            x: -self.x,
            y: -self.y,
        }
    }

    pub fn length(&self) -> f64 {
        self.distance_squared().sqrt()
    }

    pub fn normalize(&self) -> Self {
        if self.is_0() {
            panic!("0 向量，无单位向量");
        }
        let length = self.length();
        Self {
            x: self.x / length,
            y: self.y / length,
        }
    }

    pub fn is_0(&self) -> bool {
        self.x == 0.0 && self.y == 0.0
    }

    pub fn ccw_normal(&self) -> Self {
        Self {
            x: -self.y,
            y: self.x,
        }
    }

    pub fn cw_normal(&self) -> Self {
        Self {
            x: self.y,
            y: -self.x,
        }
    }

    pub fn copy(&mut self, vec: &Self) {
        self.x = vec.x;
        self.y = vec.y;
    }

    pub fn set(&mut self, x: f64, y: f64) {
        self.x = x;
        self.y = y;
    }

    pub fn set_x(&mut self, n: f64) {
        self.x = n;
    }

    pub fn set_y(&mut self, n: f64) {
        self.y = n;
    }

    pub fn dot(&self, vec: &Self) -> f64 {
        self.x * vec.x + self.y * vec.y
    }

    pub fn cross(&self, vec: &Self) -> f64 {
        self.x * vec.y - self.y * vec.x
    }

    pub fn add(&self, vec2: &Self) -> Self {
        Self {
            x: self.x + vec2.x,
            y: self.y + vec2.y,
        }
    }

    pub fn subtract(&self, vec2: &Self) -> Self {
        Self {
            x: self.x - vec2.x,
            y: self.y - vec2.y,
        }
    }

    pub fn invert(&mut self) {
        self.x = -self.x;
        self.y = -self.y;
    }

    pub fn normalized(&mut self) {
        if self.is_0() {
            panic!("0 向量，无单位向量");
        }
        let length = self.length();
        self.x = self.x / length;
        self.y = self.y / length;
    }

    pub fn multiply(&self, scalar: f64) -> Self {
        Self {
            x: self.x * scalar,
            y: self.y * scalar,
        }
    }

    pub fn rotation_transform(&self, alpha: f64) -> Self {
        let new_x = self.x * alpha.cos() - self.y * alpha.sin();
        let new_y = self.x * alpha.sin() + self.y * alpha.cos();
        Self { x: new_x, y: new_y }
    }

    pub fn angle_to(&self, v: &Self) -> f64 {
        let norm1 = self.normalize();
        let norm2 = v.normalize();
        let angle = norm1.cross(&norm2).atan2(norm1.dot(&norm2));
        if angle < 0.0 {
            angle + 2.0 * std::f64::consts::PI
        } else {
            angle
        }
    }

    pub fn projection_on(&self, v: &Self) -> Self {
        let n = v.normalize();
        let d = self.dot(&n);
        n.multiply(d)
    }
}
